#ifndef COLLECTIONS_H
#define COLLECTIONS_H

typedef int(*comparer)(void*,void*);


struct node
{
	struct node * link;
};

//NODO
typedef struct node* node;

node node_create(int T, void * value, node link);
node node_delete(node self);

void node_write(node self, int T, void * value);
void node_read(node self, int T, void * value);
void node_connect(node self, node link);
node node_getlink(node self);
int node_valueis(node self, int T, void * value, comparer comp);

//DEF
typedef struct node* def;

def def_create(int TKey, int TValue, void* key, void* value, def link);
void def_writeKey(def self, int TKey, void* key);
void def_writeValue(def self, int TKey, int TValue, void* value);
void def_write(def self, int TKey, int TValue, void* key, void* value);
def def_delete(def self);
void def_readKey(def self, int TKey, void * key);
void def_readValue(def self, int TKey, int TValue, void * value);
int def_read(def self, int TKey, int TValue, void * key, void * value);
int def_isKey(def self, int TKey, void * key);
int def_isValue(def self, int TKey, int TValue, void * value);
int def_isDef(def self, int TKey, int TValue, void * key, void * value);
void def_connect(def self, def link);
def def_getlink(def self);


//PILA
struct stack
{
	node top;
};
typedef struct stack* stack;

stack stack_create();
void stack_delete(stack self);
void stack_clear(stack self);
int stack_isempty(stack self);

void _stack_push(stack self, int T, void * value);
int _stack_pop(stack self, int T, void * value);
void _stack_peek(stack self, int T, void * value);
void _stack_removetop(stack self);

#define stack_push(self, value) \
	_stack_push(self, sizeof(typeof( value )), &value)
#define stack_pop(self, value) \
	_stack_pop(self, sizeof(typeof( value )), &value)
#define stack_peek(self, value) \
	_stack_peek(self, sizeof(typeof( value )), &value)
#define stack_popall(self, value) \
	while(stack_pop( self , value ))

//COLA
struct queue
{
	node front;
	node back;
};
typedef struct queue* queue;

queue queue_create();
void queue_delete(queue self);
void queue_clear(queue self);
int queue_isempty(queue self);


void _queue_enqueue(queue self, int T, void * value);
int _queue_dequeue(queue self, int T, void * value);
void _queue_peek(queue self, int T, void * value);

#define queue_enqueue(self, value) \
	_queue_enqueue(self, sizeof(typeof( value )), &value)
#define queue_dequeue(self, value) \
	_queue_dequeue(self, sizeof(typeof( value )), &value)
#define queue_peek(self, value) \
	_queue_peek(self, sizeof(typeof( value )), &value)
#define queue_dequeueall(self, value) \
	while(queue_dequeue( self , value ))

//LISTA (Implementacion incompleta)

struct list
{
	node first;
	node last;
};
typedef struct list* list;

list list_create();
void list_delete(list self);
void list_clear(list self);
void list_removefirst(list self);
void list_removelast(list self);

void _list_append(list self, int T, void * value);
int _list_read(list self, int T, int index, void * value);
void _list_write(list self, int T, int index, void * value);
void _list_readlast(list self, int T, void * value);
void _list_readfirst(list self, int T, void * value);
node _list_locate(list self, int index);
void _list_prepend(list self, int T, void * value);
int _list_contains(list self, int T, void * value, comparer comp);
void list_removeat(list self, int index);
int list_count(list self);
int list_isempty(list self);
int _list_indexof(list self, int T, void * value, comparer comp);
void _list_insert(list self, int T, int index, void * value);

#define list_append(self, value) \
	_list_append(self, sizeof(typeof( value )), &value)
#define list_prepend(self, value) \
	_list_prepend(self, sizeof(typeof( value )), &value)
#define list_read(self, index, value) \
	_list_read(self, sizeof(typeof( value )), index, &value)
#define list_readlast(self, value) \
	_list_readlast(self, sizeof(typeof( value )), &value)
#define list_readfirst(self, value) \
	_list_readfirst(self, sizeof(typeof( value )),  &value)
#define list_write(self, index, value) \
	_list_write(self, sizeof(typeof( value )), index,  &value)
#define list_contains(self, value, comp) \
	_list_contains(self, sizeof(typeof( value )), &value, comp)
#define list_foreach(self, index, value) \
	for(index = 0; list_read(self, index, value); index++)
#define list_indexof(self, value, comparer) \
	_list_indexof(self, sizeof(typeof( value )), &value, comparer)
#define list_insert(self, index, value) \
	_list_insert(self, sizeof(typeof( value )), index, &value)
#define list_where(self, index, value, expression) \
	for(index = 0; list_read(self, index, value); index++) if( expression )

//Diccionario (Implementacion incompleta)

struct dictionary
{
	def first;
};
typedef struct dictionary* dictionary;

struct dictionary_iterator
{
	def iterator;
};

typedef struct dictionary_iterator dictionary_iterator;

typedef void(*ifContainsKeyDo)(def,int,int,void*);

//Funciones Privadas del Diccionario
int _dictionary_containsKey(dictionary self, int TKey, void* key);
int _dictionary_containsValue(dictionary self, int TKey, int TValue, void* value);
int _dictionary_add(dictionary self, int TKey, int TValue, void* key, void* value);
int _dictionary_getValue(dictionary self, int TKey, int TValue, void* key, void* value);
int _dictionary_ifContainsKeyDo(dictionary self, int TKey, int TValue, void* key, void* value, ifContainsKeyDo f);
int _dictionary_remove(dictionary* self, int TKey, void* key);
int _dictionary_write(dictionary self, int TKey, int TValue, void* key, void* value);
#define _dictionary_foreach(self, item, expresion) \
		for(item = self->first; item != NULL && expresion; item = def_getlink(item))

//Funciones Públicas del Diccionario
dictionary dictionary_create();
void dictionary_delete(dictionary* self);
void dictionary_clear(dictionary self);
int dictionary_isEmpty(dictionary self);
int dictionary_count(dictionary self);
#define dictionary_containsKey(self, key) \
		_dictionary_containsKey(self, sizeof(typeof( key )), &key)
#define dictionary_containsValue(self, key, value) \
		_dictionary_containsValue(self, sizeof(typeof( key )), sizeof(typeof( value )), &value)
#define dictionary_add(self, key, value) \
		_dictionary_add(self, sizeof(typeof(key)), sizeof(typeof(value)), &key, &value)
#define dictionary_write(self, key, value) \
		_dictionary_write(self, sizeof(typeof(key)), sizeof(typeof(value)), &key, &value)
#define dictionary_update(self, key, value) \
		_dictionary_ifContainsKeyDo(self, sizeof(typeof(key)), sizeof(typeof(value)), &key, &value,&def_writeValue)
#define dictionary_getValue(self, key, value) \
		_dictionary_ifContainsKeyDo(self, sizeof(typeof(key)), sizeof(typeof(value)), &key, &value,&def_readValue)
#define dictionary_remove(self, key) \
		_dictionary_remove(self, sizeof(typeof(key)),&key)
#define dictionary_foreach(self, item, key, value) \
		_dictionary_foreach(self, item, def_read(item, sizeof(typeof(key)), sizeof(typeof(value)), &key, &value))

#endif
